package sopraim.presenter.services;
import sopraim.entity.User;
import java.util.ArrayList;
import java.util.Set;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.WebParam;
import sopraim.model.Model;
import sopraim.model.TextMessageDAO;
import sopraim.model.UserDAO;
import sopraim.presenter.services.util.Contact;
import sopraim.presenter.validate.AddFriendForm;
import sopraim.presenter.validate.ConnectionForm;
import sopraim.presenter.validate.SearchUserForm;
import sopraim.presenter.validate.SendTextMessageForm;
import sopraim.entity.TextMessage;
import sopraim.exceptions.UserNotExistException;
import sopraim.exceptions.WrongPasswordException;
import sopraim.presenter.validate.ReadMessageForm;
import sopraim.presenter.validate.UserCheckForm;
/**
 * User web services endpoint
 * @author INFO A1
 *
 */
@WebService( serviceName = "UserService")
public class UserService {
    Model model = Model.getInstance();
    UserDAO userDao = model.getUserDAO();
    TextMessageDAO messageDao = model.getTextMessageDAO();
    /**
     * connect user to the application
     * @param username the username
     * @param passwd the password
     * @return the user
     * @throws Exception
     */
    @WebMethod(operationName ="connect")
    public User connect(@WebParam(name = "username") String username,
            @WebParam(name = "passwd")String passwd) throws Exception{
        
        //validate form
        ConnectionForm form = new ConnectionForm(username, passwd);
        User user = userDao.findByLogin(username);
        
        //valid user
        if( user!=null && user.checkPassword(passwd)){
            userDao.updateUserStatus(user, model.getStatus("available"));
            return user;
        }
        else{
            throw new Exception("username or password not valid");
        }
        
    }
    
    /**
     * disconnect user from the application
     * @param username the user to disconnect
     * @throws Exception
     */
    @WebMethod(operationName ="disconnect")
    public void disconnect (@WebParam(name = "username") String username) throws Exception{
        User user = userDao.findByLogin(username);
        userDao.updateUserStatus(user, model.getStatus("offline"));
        
    }
    
    /**
     * get all the friends of a user
     * this is to be displayed in the client app and update when changes occurs
     * @param user the user who request the user list
     * @return the user friends list
     */
    @WebMethod(operationName = "getFriends")
    public ArrayList<User> getFriends(@WebParam(name = "user") User user) throws Exception{
        // UsernameCheckForm form = new UsernameCheckForm(user.getUsername());
        Set<User> list = userDao.findByLogin(user.getUsername()).getFriends();
        ArrayList<User> res = new ArrayList<>();
        for(User u:list){
            res.add(u);
        }
        return res;
    }
    
    /**
     * change user status (busy, absent, available)
     * @param user the user whose status changes
     * @param status the new status
     * @throws Exception
     */
    @WebMethod(operationName = "setUserStatus")
    public void setUserStatus(@WebParam(name = "user") User user, @WebParam(name = "status")
            String status) throws Exception{
        userDao.updateUserStatus(user, model.getStatus(status));
        
    }
    
    public ArrayList<String> getAllStatus(){
        return model.getStatutsDAO().getAllStatus();
    }
    public void changePassword(@WebParam(name = "user") User user, @WebParam(name = "passwd") String passwd
            ,@WebParam(name = "newPasswd") String newPasswd) throws WrongPasswordException{
        userDao.updateUserPassword(user, passwd, newPasswd);
        
    }
    /**
     * get the current user status (busy, absent, available)
     * @param username the user whose status changes
     * @return
     * @throws Exception
     */
    @WebMethod(operationName = "getUserStatus")
    public String getUserStatus(@WebParam(name = "user")User user) throws Exception{
        // UsernameCheckForm form = new UsernameCheckForm(username);
        System.out.print(user.getUsername()+"/"+user.getStatus().getId());
        return user.getStatus().getName();
    }
    
    /**
     *
     * @param localUser the local user
     * @param name name of the user to be found
     * @return a map containing the user matching the request and a boolean value to indicate if they alreaddy are on the user friend list
     * @throws Exception
     */
    @WebMethod(operationName = "searchContact")
    public ArrayList<Contact> searchContact(@WebParam(name = "localUser") User localUser, @WebParam(name = "name") String name) throws Exception{
        SearchUserForm form = new SearchUserForm(localUser,name);
        //this.checkUser(localUser);
        ArrayList<User> list = new ArrayList<>();
        list.add(userDao.findByLogin(name));
        ArrayList<Contact> res = new ArrayList<>();
        if(list!=null){
            for(User u:list){
                res.add(new Contact(u,userDao.areFriends(localUser, u)));
            }
        }
        return res;
    }
    
    /**
     *
     * @param localUser the "local" user
     * @param contactId identifier of the contact to add
     * @throws Exception when the id is incorrect
     */
    @WebMethod(operationName = "addContact")
    public void addContact(@WebParam(name = "localUser") User localUser, @WebParam(name = "contactId") int contactId)
            throws Exception {
        AddFriendForm form = new AddFriendForm(localUser, contactId);
        //this.checkUser(localUser);
        User friend = userDao.findById(contactId);
        if( friend==null){
            throw new UserNotExistException ("Friend userId do not exist in databases");
        }
        userDao.requestFriends(localUser, friend);
    }
    /**
     *
     * @param localUser the "local" user
     * @param contactId identifier of the contact to add
     * @throws Exception when the id is incorrect
     */
    @WebMethod(operationName = "removeContact")
    public void removeContact(@WebParam(name = "localUser") User localUser, @WebParam(name = "contactId") int contactId)
            throws Exception {
        AddFriendForm form = new AddFriendForm(localUser, contactId);
        //this.checkUser(localUser);
        User friend = userDao.findById(contactId);
        if( friend==null){
            throw new UserNotExistException ("Friend userId do not exist in databases");
        }
        userDao.deleteFriends(localUser, friend);
        
    }
    /**
     *
     * @param localUser the local user
     * @param friendId identifier of the friend (to be accepted)
     * @param answer true is the user accept to be friend with "friendId" user, false otherwise
     * @throws Exception if the identifier is not in the list
     */
    @WebMethod(operationName = "acceptContact")
    public void acceptContact(@WebParam(name = "localUser") User localUser, @WebParam(name = "friendId") int friendId, @WebParam(name = "answer") boolean answer)
            throws Exception {
        AddFriendForm form = new AddFriendForm(localUser, friendId);
        //this.checkUser(localUser);
        User friend = userDao.findById(friendId);
        if( friend==null){
            throw new UserNotExistException ("Friend userId do not exist in databases");
        }
        userDao.answerRequest(friend,localUser,answer);
    }
    @WebMethod(operationName = "getContactRequest")
    public ArrayList<User> getContactRequest(@WebParam(name = "localUser")User localUser){
        Set<User> list = userDao.getNotifFriendsRequest(localUser);
        ArrayList<User> res = new ArrayList<>();
        for(User u:list){
            res.add(u);
        }
        return res;
    }
    /**
     * get all the requests not anwered yet
     * @param localUser
     * @return
     */
    @WebMethod(operationName = "getNotAnsweredContactRequests")
    public ArrayList<User> getNotAnsweredContactRequests(@WebParam(name = "localUser")User localUser){
        Set<User> list = userDao.getNotifFriendsRequestNotAnswered(localUser);
        ArrayList<User> res = new ArrayList<>();
        for(User u:list){
            res.add(u);
        }
        return res;
    }
    
    /**
     *
     * @param localUser
     * @return
     * @throws Exception
     */
    @WebMethod(operationName = "getFriendAnswer")
    public String getFriendAnswer(@WebParam(name = "localUser") User localUser) throws Exception {
        UserCheckForm form = new UserCheckForm(localUser);
        this.checkUser(localUser);
        //TODO: get answer in DB
        return null;
    }
    
    
    /**
     *
     * @param localUser user that sends sthe message
     * @param receiver user targeted by the message
     * @param message content of the message to be sent
     * @throws Exception when one of the parameter is empty or not valid
     */
    @WebMethod(operationName = "sendTextMessage")
    public void sendTextMessage(@WebParam(name = "localUser") User localUser, @WebParam(name = "receiver") int receiver, @WebParam(name = "message") String message) throws Exception {
        SendTextMessageForm form = new SendTextMessageForm(localUser, receiver, message);
        this.checkUser(localUser);
        User receiverUser = userDao.findById(receiver);
        if( receiverUser==null){
            throw new UserNotExistException ("Receiver userId do not exist in databases");
        }
        messageDao.sendMessage(localUser,receiverUser,message);
    }
    
    /**
     *
     * @param localUser
     * @return
     * @throws Exception
     */
    @WebMethod(operationName = "receiveNewTextMessages")
    public ArrayList<TextMessage> receiveNewTextMessages(@WebParam(name = "localUser") User localUser)  throws Exception {
        UserCheckForm form = new UserCheckForm(localUser);
        this.checkUser(localUser);
        Set<TextMessage> messages = messageDao.getNewMessages(localUser);
        ArrayList<TextMessage> res = new ArrayList<>();
        for(TextMessage m : messages){
            res.add(m);
        }
        return res;
    }
    
    /**
     *
     * @param userId
     * @param messageId
     * @throws Exception
     *
     * @WebMethod(operationName = "receiveMessage")
     * public void receiveMessage(@WebParam(name = "userId") int userId, @WebParam(name = "messageId") long messageId) throws Exception {
     * ReadMessageForm form = new ReadMessageForm(userId, messageId);
     * User user = userDao.findById(userId);
     * if( user==null){
     * throw new Exception ("User do not exist in databases");
     * }
     * TextMessage message=null;//messageDao.findById(messageId); TODO CHANGE WHEN FUNCTION AVAILABLE
     * if( message==null){
     * throw new Exception ("Message do not exist in databases");
     * }
     * //messageDao.receiveMessage(user, message);
     * }*/
    
    /**
     *
     * @param localUser
     * @param messageId
     * @throws Exception
     */
    @WebMethod(operationName = "readMessage")
    public void readMessage(@WebParam(name = "localUser") User localUser, @WebParam(name = "messageId") long messageId) throws Exception{
        ReadMessageForm form = new ReadMessageForm(localUser, messageId);
        this.checkUser(localUser);
        TextMessage message=null;//messageDao.findById(messageId); TODO CHANGE WHEN FUNCTION AVAILABLE
        if( message==null){
            throw new Exception ("Message do not exist in databases");
        }
        messageDao.readMessage(localUser, message);
    }
    
    @WebMethod(operationName = "getHistory")
    public ArrayList<TextMessage> getHistory(@WebParam(name = "localUser") User localUser){
        String link = null;
        //get all the message of this user
        ArrayList<TextMessage> list = messageDao.getAllMessage(localUser);
        
        return list;
    }
    @WebMethod(operationName = "getAllMessageSendTo")
    public ArrayList<TextMessage> getAllMessageSendTo(@WebParam(name = "localUser") User localUser,
            @WebParam(name = "remoteUser") User remoteUser){
        //get all the message of this user
        ArrayList<TextMessage> list = messageDao.getMessagesSento(localUser, remoteUser);
        return list;
    }
    @WebMethod(operationName = "getAllMessageReceivedFrom")
    public ArrayList<TextMessage> getAllMessageReceivedFrom(@WebParam(name = "localUser") User localUser,
            @WebParam(name = "remoteUser") User remoteUser){
        //get all the message of this user
        ArrayList<TextMessage> list = messageDao.getMessagesReceivedFrom(localUser, remoteUser);
        return list;
    }
    /**
     *
     * @param localUser
     * @return
     * @throws Exception
     */
    @WebMethod(operationName = "getNewMessageState")
    public String getNewMessageState(@WebParam(name = "localUser") User localUser) throws Exception{
        UserCheckForm form = new UserCheckForm(localUser);
        this.checkUser(localUser);
        
        return null;
    }
    
    
    
    private void checkUser(User usr) throws UserNotExistException{
        User validUsr= userDao.findById(usr.getId());
        if (validUsr==null){
            throw new UserNotExistException("User do not exist in database");
        }
        if (!validUsr.getPassword().equals(usr.getPassword())|| !validUsr.getUsername().equals(usr.getUsername())){
            throw new UserNotExistException("User ids are incorrect");
        }
    }
    
}
